package cmd

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/spf13/cobra"
	"golang.org/x/crypto/ssh"
)

var (
	host                     string
	port                     int
	user                     string
	password                 string
	sourceFile               string
	reboot                   bool
	installFrontendFlag      bool
	installPythonPackageFlag bool
	installOrangepiCliFlag   bool
)

var updateCmd = &cobra.Command{
	Use:   "update",
	Short: "更新远程设备上的程序",
	Long:  `通过SCP将程序传输到远程设备并安装`,
	RunE: func(cmd *cobra.Command, args []string) error {
		// 计算总步骤数
		totalSteps := 0
		if installOrangepiCliFlag {
			totalSteps++
		}
		if installPythonPackageFlag {
			totalSteps++
		}
		if installFrontendFlag {
			totalSteps++
		}
		if reboot {
			totalSteps++
		}
		currentStep := 0

		fmt.Println("开始清除已知主机密钥")
		// 在 updateCmd 的 RunE 函数中，在创建 SSH 连接之前添加
		// 清除可能存在的旧密钥
		if err := cleanKnownHosts(host); err != nil {
			return fmt.Errorf("清除已知主机密钥失败: %v", err)
		}
		// 创建SSH客户端配置
		config := &ssh.ClientConfig{
			User: user,
			Auth: []ssh.AuthMethod{
				ssh.Password(password),
			},
			HostKeyCallback: ssh.InsecureIgnoreHostKey(),
			Timeout:         30 * time.Second,
		}

		// 连接到远程服务器
		client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", host, port), config)
		if err != nil {
			return fmt.Errorf("连接到远程服务器失败: %v", err)
		}
		defer client.Close()

		// 复制并安装基础程序
		if installOrangepiCliFlag {
			currentStep++
			fmt.Printf("开始 [%d/%d] 基础程序安装\n", currentStep, totalSteps)

			// 复制命令
			fmt.Println("开始复制文件")
			if err := scpFile(client, sourceFile, "/root/orangepi-cli"); err != nil {
				return fmt.Errorf("复制文件失败: %v", err)
			}
			// 执行安装命令
			fmt.Println("开始执行安装命令")
			if err := executeRemoteCommand(client, "/root/orangepi-cli install command"); err != nil {
				return fmt.Errorf("执行安装命令失败: %v", err)
			}
			fmt.Println("安装命令执行完成")
			// 安装服务
			fmt.Println("开始安装服务")
			if err := executeRemoteCommand(client, "/root/orangepi-cli install service"); err != nil {
				return fmt.Errorf("安装服务失败: %v", err)
			}
			fmt.Println("服务安装完成")
			fmt.Printf("完成 [%d/%d] 基础程序安装\n", currentStep, totalSteps)
		} else {
			fmt.Println("不安装 orangepi-cli")
		}

		// 安装python包
		if installPythonPackageFlag {
			currentStep++
			fmt.Printf("开始 [%d/%d] Python包安装\n", currentStep, totalSteps)
			if err := installPythonPackage(client); err != nil {
				return err
			}
			fmt.Printf("完成 [%d/%d] Python包安装\n", currentStep, totalSteps)
		} else {
			fmt.Println("不安装python包")
		}

		// 安装前端
		if installFrontendFlag {
			currentStep++
			fmt.Printf("开始 [%d/%d] 前端安装\n", currentStep, totalSteps)
			if err := installFrontend(client); err != nil {
				return err
			}
			fmt.Printf("完成 [%d/%d] 前端安装\n", currentStep, totalSteps)
		} else {
			fmt.Println("不安装前端")
		}

		if reboot {
			currentStep++
			fmt.Printf("开始 [%d/%d] 设备重启\n", currentStep, totalSteps)
			if err := rebootDevice(client); err != nil {
				return err
			}
			fmt.Printf("完成 [%d/%d] 设备重启\n", currentStep, totalSteps)
		} else {
			fmt.Println("更新完成, 设备未重启")
		}
		return nil
	},
}

func cleanKnownHosts(host string) error {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return fmt.Errorf("获取用户主目录失败: %v", err)
	}

	knownHostsFile := filepath.Join(homeDir, ".ssh", "known_hosts")

	// 如果文件不存在，直接返回
	if _, err := os.Stat(knownHostsFile); os.IsNotExist(err) {
		return nil
	}

	// 读取现有的 known_hosts 文件
	content, err := os.ReadFile(knownHostsFile)
	if err != nil {
		return fmt.Errorf("读取 known_hosts 文件失败: %v", err)
	}

	var newLines []string
	lines := strings.Split(string(content), "\n")

	// 过滤掉包含目标主机的行
	for _, line := range lines {
		if !strings.Contains(line, host) {
			newLines = append(newLines, line)
		}
	}

	// 写回文件
	err = os.WriteFile(knownHostsFile, []byte(strings.Join(newLines, "\n")), 0600)
	if err != nil {
		return fmt.Errorf("写入 known_hosts 文件失败: %v", err)
	}

	fmt.Printf("已从 known_hosts 清除主机 %s 的密钥\n", host)
	return nil
}

func rebootDevice(client *ssh.Client) error {
	var ignoredErrors = []string{
		"connection",
		"closed",
		"broken pipe",
		"reset by peer",
		"remote command exited without exit status or exit signal",
		// 添加其他需要忽略的错误信息
	}

	fmt.Println("准备重启设备...")
	if err := executeRemoteCommand(client, "reboot"); err != nil {
		errMsg := strings.ToLower(err.Error())
		shouldIgnore := false
		for _, ignored := range ignoredErrors {
			if strings.Contains(errMsg, ignored) {
				shouldIgnore = true
				break
			}
		}
		if !shouldIgnore {
			return fmt.Errorf("重启设备失败: %v", err)
		}
	}

	fmt.Println("设备正在重启...")
	return nil
}

func installFrontend(client *ssh.Client) error {
	// 检查当前目录下的 dist.zip 压缩包是否存在
	if _, err := os.Stat("dist.zip"); err == nil {
		steps := []struct {
			cmd    string
			errMsg string
		}{
			{"", "复制前端压缩包文件失败"}, // 特殊处理SCP
			{"unzip -o /root/dist.zip -d /dist", "解压前端压缩包失败"},
			{"rm -f /root/dist.zip", "删除前端压缩包失败"},
		}

		// 特殊处理第一步：文件复制
		if err := scpFile(client, "dist.zip", "/root/dist.zip"); err != nil {
			return fmt.Errorf("%s: %v", steps[0].errMsg, err)
		}

		// 执行其余步骤
		for _, step := range steps[1:] {
			if err := executeRemoteCommand(client, step.cmd); err != nil {
				return fmt.Errorf("%s: %v", step.errMsg, err)
			}
		}

		fmt.Println("前端安装完成")
	}
	return nil
}

func installPythonPackage(client *ssh.Client) error {
	// 检查当前目录下 robot_module.zip 压缩包是否存在
	if _, err := os.Stat("robot_module.zip"); err == nil {
		// 复制并安装Python包
		steps := []struct {
			cmd    string
			errMsg string
		}{
			{"", "复制python包压缩包文件失败"}, // 特殊处理SCP
			// 安装pip包, python3 pip.pyz pip-24.2-py3-none-any.whl
			{"python3 /root/pip.pyz install /root/pip-24.2-py3-none-any.whl", "安装pip包失败"},
			// 打印pip版本
			{"pip3 --version", "打印pip版本失败"},
			// 通过pip3安装 setuptools
			{"pip3 install /root/setuptools-75.2.0-py3-none-any.whl", "安装setuptools失败"},
			// 卸载my-robot-module库
			{"rm -rf /root/.local/lib/python3.8/site-packages/my_robot_module-*", "卸载my-robot-module库失败"},
			// 解压python包压缩包
			{"unzip -o /root/robot_module.zip -d /root/robot_module", "解压python包压缩包失败"},
			// 编译python包
			{"cd /root/robot_module && python3 setup.py build", "编译python包失败"},
			// 安装python包
			{"cd /root/robot_module && python3 setup.py install --user", "安装python包失败"},
			// 删除python包压缩包
			{"rm -f /root/robot_module.zip", "删除python包压缩包失败"},
			// 删除python包解压文件夹
			{"rm -rf /root/robot_module", "删除python包解压文件夹失败"},
		}

		// 特殊处理第一步：文件复制
		fmt.Println("开始复制文件")
		files := []string{
			"pip.pyz",
			"pip-24.2-py3-none-any.whl",
			"setuptools-75.2.0-py3-none-any.whl",
			"robot_module.zip",
		}

		for _, file := range files {
			if err := scpFile(client, file, "/root/"+file); err != nil {
				return fmt.Errorf("%s: %v", steps[0].errMsg, err)
			}
		}

		// 安装依赖工具 setuptools
		if err := installSetupTools(client); err != nil {
			return err
		}

		// 执行其余步骤
		for _, step := range steps[1:] {
			if err := executeRemoteCommand(client, step.cmd); err != nil {
				return fmt.Errorf("%s: %v", step.errMsg, err)
			}
		}

		fmt.Println("python包安装完成")
	}
	return nil
}

func installSetupTools(client *ssh.Client) error {
	// 检查 setuptools 压缩包文件
	if _, err := os.Stat("setuptools-75.2.0.tar.gz"); err == nil {
		// 复制文件到远程根目录
		if err := scpFile(client, "setuptools-75.2.0.tar.gz", "/root/setuptools-75.2.0.tar.gz"); err != nil {
			return fmt.Errorf("复制setuptools压缩包文件失败: %v", err)
		}

		// 解压、编译和安装
		commands := []struct {
			cmd    string
			errMsg string
		}{
			{"tar -xzf /root/setuptools-75.2.0.tar.gz -C /root", "解压setuptools压缩包失败"},
			{"cd /root/setuptools-75.2.0 && python3 setup.py build", "编译setuptools失败"},
			{"cd /root/setuptools-75.2.0 && python3 setup.py install --user", "安装setuptools失败"},
		}

		for _, command := range commands {
			if err := executeRemoteCommand(client, command.cmd); err != nil {
				return fmt.Errorf("%s: %v", command.errMsg, err)
			}
		}
	}
	return nil
}

func scpFile(client *ssh.Client, localPath, remotePath string) error {
	fmt.Printf("开始复制文件: %s -> %s\n", localPath, remotePath)
	// 打开本地文件
	localFile, err := os.Open(localPath)
	if err != nil {
		return fmt.Errorf("打开本地文件失败: %v", err)
	}
	defer localFile.Close()

	// 获取文件信息
	stat, err := localFile.Stat()
	if err != nil {
		return fmt.Errorf("获取文件信息失败: %v", err)
	}
	fmt.Printf("文件大小: %d 字节\n", stat.Size())
	// 创建新的会话
	session, err := client.NewSession()
	if err != nil {
		return fmt.Errorf("创建会话失败: %v", err)
	}
	defer session.Close()

	fmt.Println("SSH会话创建成功")

	tempPath := fmt.Sprintf("/tmp/temp_%d", time.Now().UnixNano())
	errCh := make(chan error, 1)

	// 准备复制文件
	go func() {
		w, err := session.StdinPipe()
		if err != nil {
			errCh <- fmt.Errorf("获取stdin管道失败: %v", err)
			return
		}
		defer w.Close()

		fmt.Printf("开始传输文件数据到文件 %s...\n", tempPath)
		fmt.Fprintf(w, "C0755 %d %s\n", stat.Size(), filepath.Base(tempPath))
		written, err := io.Copy(w, localFile)
		if err != nil {
			errCh <- fmt.Errorf("文件传输出错: %v (已传输 %d 字节)", err, written)
			return
		}
		fmt.Printf("已传输 %d 字节数据\n", written)
		fmt.Fprint(w, "\x00")
		errCh <- nil
	}()

	// 先复制到用户目录
	var stderr bytes.Buffer
	session.Stderr = &stderr
	if err := session.Run(fmt.Sprintf("scp -t %s", tempPath)); err != nil {
		return fmt.Errorf("执行scp命令失败: %v, stderr: %s", err, stderr.String())
	}

	if err := <-errCh; err != nil {
		return err
	}

	// 创建新会话移动文件
	moveSession, err := client.NewSession()
	if err != nil {
		return fmt.Errorf("创建移动文件会话失败: %v", err)
	}
	defer moveSession.Close()

	// 直接移动文件
	fmt.Printf("开始移动文件: %s -> %s\n", tempPath, remotePath)
	var moveStderr bytes.Buffer
	moveSession.Stderr = &moveStderr
	if err := moveSession.Run(fmt.Sprintf("mv %s %s", tempPath, remotePath)); err != nil {
		return fmt.Errorf("移动文件失败: %v, stderr: %s", err, moveStderr.String())
	}

	fmt.Println("文件复制成功完成")
	return nil
}

func executeRemoteCommand(client *ssh.Client, command string) error {
	session, err := client.NewSession()
	if err != nil {
		return fmt.Errorf("创建会话失败: %v", err)
	}
	defer session.Close()

	// 捕获标准输出和标准错误
	var stdout, stderr bytes.Buffer
	session.Stdout = &stdout
	session.Stderr = &stderr

	err = session.Run(command)
	if err != nil {
		return fmt.Errorf("执行命令失败: %v\n标准输出: %s\n标准错误: %s", err, stdout.String(), stderr.String())
	}

	fmt.Printf("命令执行成功，输出: %s\n", stdout.String())
	return nil
}

func init() {
	rootCmd.AddCommand(updateCmd)

	updateCmd.Flags().StringVar(&host, "host", "192.168.1.10", "远程设备的IP地址")
	updateCmd.Flags().IntVar(&port, "port", 22, "SSH端口")
	updateCmd.Flags().StringVar(&user, "user", "root", "SSH用户名")
	updateCmd.Flags().StringVar(&password, "password", "orangepi", "SSH密码")
	updateCmd.Flags().StringVar(&sourceFile, "source", "orangepi-cli-arm", "要更新的应用路径")
	updateCmd.Flags().BoolVar(&reboot, "reboot", true, "更新后是否重启设备")
	// 新增是否安装前端参数
	updateCmd.Flags().BoolVar(&installFrontendFlag, "frontend", true, "是否安装前端")
	// 新增是否安装python包参数
	updateCmd.Flags().BoolVar(&installPythonPackageFlag, "python", true, "是否安装python包")
	// 新增是否安装 orangepi-cli 参数
	updateCmd.Flags().BoolVar(&installOrangepiCliFlag, "orangepi-cli", true, "是否安装 orangepi-cli")
}
